const express = require('express');
const router = express.Router();
const swaggerUi = require('swagger-ui-express');
const swaggerDocs = require('@/middleware/swagger.middleware'); // 引入之前创建的Swagger配置

// 设置路由，返回 Swagger JSON 文档
router.get('/swagger.json', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerDocs);
});

// 下载 Swagger JSON 文档方便后面导入到调试工具中
router.get('/download-swagger.json', (req, res) => {
  // 将JSON对象转换成字符串
  const jsonString = JSON.stringify(swaggerDocs);

  // 设置响应头，告诉浏览器这是一个要下载的文件
  res.setHeader('Content-Disposition', 'attachment; filename=swagger.json');
  res.setHeader('Content-Type', 'application/json');

  // 发送JSON字符串作为响应体
  res.send(jsonString);
});

// 获取所有分组：springdoc-open格式
router.get('/v3/api-docs/swagger-config', (req, res) => {
  const groups = [{
    name: '全部',
    location: `/api-docs/全部`,
    url: `/api-docs/全部`,
    swaggerVersion: '3.0.0',
    servicePath: '/api'
  }];

  // 遍历所有路径，提取分组信息
  const uniqueTags = new Set();
  for (const path in swaggerDocs.paths) {
    const pathObject = swaggerDocs.paths[path];
    for (const method in pathObject) {
      const operation = pathObject[method];
      if (operation && operation.tags) {
        operation.tags.forEach(tag => {
          uniqueTags.add(tag);
        });
      }
    }
  }

  // 生成分组资源
  uniqueTags.forEach(tag => {
    groups.push({
      name: tag,
      location: `/api-docs/${tag}`,
      url: `/api-docs/${tag}`,
      swaggerVersion: '3.0.0',
      servicePath: '/api'
    });
  });
  swaggerDocs.urls = groups
  res.setHeader('Content-Type', 'application/json');
  res.json(swaggerDocs);
});

// 获取所有分组：springfox格式
router.get('/swagger-resources', (req, res) => {
  const groups = [{
    name: '全部',
    location: `/api-docs/全部`,
    url: `/api-docs/全部`,
    swaggerVersion: '3.0.0',
    servicePath: '/api'
  }];

  // 遍历所有路径，提取分组信息
  const uniqueTags = new Set();
  for (const path in swaggerDocs.paths) {
    const pathObject = swaggerDocs.paths[path];
    for (const method in pathObject) {
      const operation = pathObject[method];
      if (operation && operation.tags) {
        operation.tags.forEach(tag => {
          uniqueTags.add(tag);
        });
      }
    }
  }

  // 生成分组资源
  uniqueTags.forEach(tag => {
    groups.push({
      name: tag,
      location: `/api-docs/${tag}`,
      url: `/api-docs/${tag}`,
      swaggerVersion: '3.0.0',
      servicePath: '/api'
    });
  });

  res.json(groups);
});

// 递归解析 $ref
function resolveRefs(obj, docs) {
  if (typeof obj !== 'object' || obj === null) return obj;

  if ('$ref' in obj) {
    const refPath = obj['$ref'].split('/').slice(1);
    let current = docs;
    for (const part of refPath) {
      current = current[part];
    }
    return resolveRefs(current, docs);
  }

  for (const key in obj) {
    obj[key] = resolveRefs(obj[key], docs);
  }

  return obj;
}

// 动态生成分组的 Swagger 文档
router.get('/api-docs/:groupName?', (req, res) => {
  const groupName = req.params.groupName || '全部';

  // 初始化分组规范
  let groupSpec = {
    openapi: swaggerDocs.openapi,
    info: swaggerDocs.info,
    servers: swaggerDocs.servers,
    paths: {},
    components: {}
  };

  if (groupName.toLowerCase() === '全部') {
    // 如果请求的是“全部”分组，直接返回完整的 Swagger 文档
    groupSpec = resolveRefs(swaggerDocs, swaggerDocs);
  } else {
    // 创建一个映射来跟踪哪些组件被使用了
    const usedComponents = {
      schemas: new Set(),
      responses: new Set(),
      parameters: new Set(),
      requestBodies: new Set(),
      headers: new Set(),
      securitySchemes: new Set(),
      links: new Set(),
      callbacks: new Set()
    };

    // 遍历所有路径，找到与分组匹配的操作
    for (const [path, pathObject] of Object.entries(swaggerDocs.paths)) {
      for (const [method, operation] of Object.entries(pathObject)) {
        if (operation.tags && operation.tags.includes(groupName)) {
          // 添加路径到分组规范
          if (!groupSpec.paths[path]) {
            groupSpec.paths[path] = {};
          }
          groupSpec.paths[path][method] = operation;

          // 收集使用的组件
          if (operation.responses) {
            for (const [responseCode, response] of Object.entries(operation.responses)) {
              if (response.$ref) {
                usedComponents.responses.add(response.$ref.split('/').pop());
              } else if (response.content) {
                for (const [contentType, content] of Object.entries(response.content)) {
                  if (content.schema && content.schema.$ref) {
                    usedComponents.schemas.add(content.schema.$ref.split('/').pop());
                  }
                }
              }
            }
          }
          if (operation.parameters) {
            for (const param of operation.parameters) {
              if (param.$ref) {
                usedComponents.parameters.add(param.$ref.split('/').pop());
              }
            }
          }
          if (operation.requestBody && operation.requestBody.$ref) {
            usedComponents.requestBodies.add(operation.requestBody.$ref.split('/').pop());
          }
        }
      }
    }

    // 根据使用的组件映射来填充分组规范中的组件部分
    for (const [componentType, componentItems] of Object.entries(swaggerDocs.components)) {
      for (const [componentName, componentValue] of Object.entries(componentItems)) {
        if (usedComponents[componentType].has(componentName)) {
          if (!groupSpec.components[componentType]) {
            groupSpec.components[componentType] = {};
          }
          groupSpec.components[componentType][componentName] = componentValue;

          // 递归处理嵌套的 $ref
          if (componentType === 'schemas' && componentValue.properties) {
            for (const [propName, propValue] of Object.entries(componentValue.properties)) {
              if (propValue.$ref) {
                usedComponents.schemas.add(propValue.$ref.split('/').pop());
              }
            }
          }
        }
      }
    }

    // 解析并展开所有的 $ref
    groupSpec = resolveRefs(groupSpec, swaggerDocs);
  }

  // 返回分组规范
  res.json(groupSpec);
});

router.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocs));

module.exports = router;